package com.hy.video.monitor.rest;

import com.hy.video.monitor.domain.Permission;
import com.hy.video.monitor.domain.Role;
import com.hy.video.monitor.domain.User;
import com.hy.video.monitor.domain.dto.*;
import com.hy.video.monitor.service.UserService;
import com.hy.video.monitor.service.admin.PermissionAdminService;
import com.hy.video.monitor.service.admin.RoleAdminService;
import com.hy.video.monitor.service.admin.UserAdminService;
import com.hy.video.monitor.service.validation.RoleValidationService;
import com.hy.video.monitor.service.validation.UserValidationService;
import com.hy.video.monitor.domain.dto.*;
import com.querydsl.core.types.Predicate;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.binding.QuerydslPredicate;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Set;

/**
 * @program: mcros-ca
 * @description
 * @author: 张三少
 * @create: 2022-04-21 10:41
 **/

@Api(tags = "用户角色权限管理")
@CrossOrigin
@RestController
@RequiredArgsConstructor
@RequestMapping("/admin")
public class AdminResource {

//    private final UserService userService;
//
//    @GetMapping("/users")
//    Page<User> findAll(Pageable pageable) {
//        return userService.findAll(pageable);
//    }
//
//    @GetMapping("/validation/email")
//    public boolean validateEmail(@RequestParam String email, @RequestParam String username) {
//        return userService.isEmailExistedAndUsernameIsNot(email, username);
//    }
//
//    @GetMapping("/validation/mobile")
//    public boolean validateMobile(@RequestParam String mobile, @RequestParam String username) {
//        return userService.isMobileExistedAndUsernameIsNot(mobile, username);
//    }
    private final UserService userService;
    private final UserAdminService userAdminService;
    private final RoleAdminService roleAdminService;
    private final PermissionAdminService permissionAdminService;
    private final UserValidationService userValidationService;
    private final RoleValidationService roleValidationService;

    @ApiOperation("组合条件分页查询用户列表")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
//            @ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
//    })
    @GetMapping("/users") // QueryDSL自定义实体映射，Predicate多条件查询
    public Page<UserDto> findAllUsers(@QuerydslPredicate(root = User.class) Predicate predicate, @RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size) {
        return userAdminService.findAll(predicate, PageRequest.of(page-1,size))
            .map(user -> UserDto.fromUser.apply(user));
    }

    @ApiOperation("根据用户名查询用户")
    @GetMapping("/users/{username}")
    public UserDto findByUsername(@PathVariable String username) {
        return userAdminService.findByUsername(username)
            .map(user -> UserDto.fromUser.apply(user))
            .orElseThrow();
    }

    @ApiOperation("管理员直接创建用户")
    @PostMapping("/users")
    public UserDto createUser(@Valid @RequestBody CreateUserDto createUserDto) {
        userValidationService.validateUserUniqueFields(createUserDto.getUsername(), createUserDto.getEmail(), createUserDto.getMobile());
        val user = userAdminService.createUser(createUserDto);
        return UserDto.fromUser.apply(user);
    }

    @ApiOperation("更新用户")
    @PutMapping("/users/{username}")
    public UserDto updateUser(@PathVariable String username, @Valid @RequestBody UserProfileDto userProfileDto) {
        return userService.findOptionalByUsername(username)
            .map(user -> {
                val toSave = user
                    .withName(userProfileDto.getName())
                    .withEmail(userProfileDto.getEmail())
                    .withMobile(userProfileDto.getMobile());
                val saved = userService.saveUser(toSave);
                return UserDto.fromUser.apply(saved);
            })
            .orElseThrow();
    }

    @ApiOperation("切换用户是否激活状态")
    @PutMapping("/users/{username}/enabled")
    public UserDto toggleUserEnabled(@PathVariable String username) {
        val user = userAdminService.toggleEnabled(username);
        return UserDto.fromUser.apply(user);
    }

    @ApiOperation("查询指定用户的可分配角色列表")
    @GetMapping("/users/{username}/roles/available")
    public Set<Role> getUserAvailableRoles(@PathVariable String username) {
        return userAdminService.findAvailableRolesByUserId(username);
    }

    @ApiOperation("给用户设置角色")
    @PutMapping("/users/{username}/roles")
    public UserDto updateUserRoles(@PathVariable String username, @RequestBody List<Long> roleIds) {
        val user = userAdminService.updateRoles(username, roleIds);
        return UserDto.fromUser.apply(user);
    }

    @ApiOperation("组合条件分页查询角色列表")
    @GetMapping("/roles")
    public Page<RoleDto> findAllRoles(@QuerydslPredicate(root = Role.class) Predicate predicate, @RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size) {
        return roleAdminService.findAll(predicate, PageRequest.of(page-1,size)).map(role -> RoleDto.fromRole.apply(role));
    }

    @ApiOperation("添加角色")
    @PostMapping("/roles")
    public RoleDto addRole(@Valid @RequestBody CreateOrUpdateRoleDto createOrUpdateRoleDto) {
        val role = roleAdminService.createRole(createOrUpdateRoleDto);
        return RoleDto.fromRole.apply(role);
    }

    @ApiOperation("根据角色ID查询角色信息")
    @GetMapping("/roles/{roleId}")
    public RoleDto getRole(@PathVariable Long roleId) {
        return roleAdminService.findById(roleId)
            .map(role -> RoleDto.fromRole.apply(role))
            .orElseThrow();
    }

    @ApiOperation("根据角色ID修改角色信息")
    @PutMapping("/roles/{roleId}")
    public RoleDto updateRole(@PathVariable Long roleId, @Valid @RequestBody CreateOrUpdateRoleDto createOrUpdateRoleDto) {
        val role = roleAdminService.updateRole(roleId, createOrUpdateRoleDto);
        return RoleDto.fromRole.apply(role);
    }

    @ApiOperation("根据角色ID删除角色信息")
    @DeleteMapping("/roles/{roleId}")
    public void deleteRole(@PathVariable Long roleId) {
        roleAdminService.deleteRole(roleId);
    }

    @ApiOperation("根据角色ID查询可用权限")
    @GetMapping("/roles/{roleId}/permissions/available")
    public Set<Permission> findAvailablePermissions(@PathVariable Long roleId) {
        return roleAdminService.findAvailablePermissions(roleId);
    }


    @ApiOperation("更新指定角色ID权限")
    @PutMapping("/roles/{roleId}/permissions")
    public RoleDto removeRolePermissions(@PathVariable Long roleId, @RequestBody List<Long> permissionIds) {
        val role = roleAdminService.updatePermissions(roleId, permissionIds);
        return RoleDto.fromRole.apply(role);
    }

    @ApiOperation("组合条件分页查询权限列表")
    @GetMapping("/permissions")
    public Page<PermissionsDto> findAllPermissions(@QuerydslPredicate(root = Permission.class) Predicate predicate, @RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size) {
        return permissionAdminService.findAll(predicate, PageRequest.of(page-1,size)).map(permission -> PermissionsDto.fromPermissions.apply(permission));

    }

    @ApiOperation("编辑用户的场景下，判断电子邮件是否重复。需要规避用户本身的邮件地址。")
    @GetMapping("/validation/email")
    public boolean validateEmail(@RequestParam String email, @RequestParam String username) {
        return userValidationService.isEmailExistedAndUsernameIsNot(email, username);
    }

    @ApiOperation("编辑用户的场景下，判断手机号是否重复。需要规避用户本身的手机号。")
    @GetMapping("/validation/mobile")
    public boolean validateMobile(@RequestParam String mobile, @RequestParam String username) {
        return userValidationService.isMobileExistedAndUsernameIsNot(mobile, username);
    }

    @ApiOperation("根据角色名称校验角色是否存在")
    @GetMapping("/validation/role-name")
    public boolean validateRoleName(@RequestParam String roleName) {
        return roleValidationService.isRoleNameExisted(roleName);
    }

    @ApiOperation("根据角色ID和角色名称校验角色是否存在")
    @GetMapping("/validation/roles/{id}/role-name")
    public boolean validateRoleNameNotSelf(@PathVariable Long id, @RequestParam String roleName) {
        return roleValidationService.isRoleNameExistedAndIdIsNot(roleName, id);
    }

}
